﻿using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

using Stock.Util;
using Stock.Model;
using System;
using HtmlAgilityPack;

namespace Stock.Service
{
    public abstract class BaseService
    {
        private string baseUrl;
        public BaseService()
        {

        }

        public BaseService(string url)
        {
            baseUrl = url;
        }

        public string BaseUrl
        {
            get => BaseUrl;
            set => baseUrl = value;
        }

        public virtual string GetFilePath(string fileName)
        {
            return FileUtil.GetFilePath($"Data\\{fileName}");
        }

        public virtual async Task<ApiResult<T>> GetAsync<T>(string url, Dictionary<string, object> parameters = null, bool useBaseUrl = true, Action<HttpItem> action = null)
        {
            return await Task.Factory.StartNew(() =>
            {
                return Get<T>(url, parameters, useBaseUrl, action);
            });
        }

        public virtual ApiResult<T> Get<T>(string url, Dictionary<string, object> parameters = null, bool useBaseUrl = true, Action<HttpItem> action = null)
        {
            var result = GetString(url, parameters, useBaseUrl, action);
            if (result.Flag)
            {
                return ApiResult<T>.Success(StringUtil.Parse<T>(result.Data));
            }
            return ApiResult<T>.Fail(result.Message);
        }

        public virtual async Task<ApiResult<string>> GetStringAsync(string url, Dictionary<string, object> parameters = null, bool useBaseUrl = true, Action<HttpItem> action = null)
        {
            return await Task.Factory.StartNew(() =>
            {
                return GetString(url, parameters, useBaseUrl, action);
            });
        }

        public virtual ApiResult<string> GetString(string url, Dictionary<string, object> parameters = null, bool useBaseUrl = true, Action<HttpItem> action = null)
        {
            HttpItem item = new HttpItem
            {
                URL = GetUrl(url, parameters, useBaseUrl)
            };

            action?.Invoke(item);

            HttpResult result = HttpUtil.Instance.Request(item);
            if (result.Success)
            {
                return ApiResult<string>.Success(result.Html);
            }
            else
            {
                var res = StringUtil.Parse<ErrorResponse>(result.Html);
                string msg = "网络错误";
                if (res != null)
                {
                    msg = res.Message;
                }
                return ApiResult<string>.Fail(msg);
            }
        }

        public virtual async Task<ApiResult<string>> DownloadFileAsync(string url, string filePath, Dictionary<string, object> parameters = null, bool useBaseUrl = true, Action<double, double> downloadProcessing = null, Action<double> downlaodCompleted = null)
        {
            return await Task.Factory.StartNew(() => DownloadFile(url, filePath, parameters, useBaseUrl, downloadProcessing, downlaodCompleted));
        }

        public virtual ApiResult<string> DownloadFile(string url, string filePath, Dictionary<string, object> parameters = null, bool useBaseUrl = true, Action<double, double> downloadProcessing = null, Action<double> downlaodCompleted = null)
        {
            HttpItem item = new HttpItem
            {
                IsDownloadFile = true,
                ContentType = "application/octet-stream",
                Allowautoredirect = false,
                URL = GetUrl(url, parameters, useBaseUrl),
                SaveFilePath = filePath,
                DownloadProcessing = downloadProcessing,
                DownloadCompleted = downlaodCompleted
            };

            HttpResult result = HttpUtil.Instance.Request(item);
            if (result.Success)
            {
                return ApiResult<string>.Success("下载成功");
            }
            else
            {
                return ApiResult<string>.Fail("下载失败");
            }
        }

        private string GetUrl(string url, Dictionary<string, object> parameters, bool useBaseUrl = true)
        {
            StringBuilder sb = new StringBuilder();
            if (useBaseUrl && !string.IsNullOrEmpty(baseUrl))
            {
                sb.Append(baseUrl);
            }
            sb.Append(url);
            if (parameters != null && parameters.Count > 0)
            {
                if (!sb.ToString().Contains("?"))
                {
                    sb.Append("?");
                }
                int index = 0;
                foreach (var item in parameters)
                {
                    sb.AppendFormat("{0}={1}", item.Key, item.Value);
                    if (index < parameters.Count - 1)
                    {
                        sb.Append("&");
                    }
                }
            }
            return sb.ToString();
        }

        #region HTML
        protected string GetNodeAttrText(HtmlNode node, string xpath, string attrName)
        {
            var child = GetNode(node, xpath);
            if (child != null)
            {
                var attrs = child.Attributes;
                if (attrs != null)
                {
                    var attr = child.Attributes[attrName];
                    if (attr != null)
                    {
                        return attr.Value;
                    }
                }
            }
            return string.Empty;
        }

        protected string GetNodeText(HtmlNode node, string xpath)
        {
            var child = GetNode(node, xpath);
            if (child != null)
            {
                return child.InnerText.Trim();
            }
            return string.Empty;
        }

        protected HtmlNode GetNode(HtmlNode node, string xpath)
        {
            return node.SelectSingleNode(xpath);
        }

        protected HtmlNodeCollection GetNodeList(HtmlNode node, string xpath)
        {
            return node.SelectNodes(xpath);
        }
        #endregion
    }
}
